package com.hunttown.mes.manage.controller;

import com.hunttown.mes.common.keys.KeyConstants;
import com.hunttown.mes.common.OperateCode;
import com.hunttown.mes.common.cache.Cache;
import com.hunttown.mes.manage.cache.ManageRightRoleCacheData;
import com.hunttown.mes.manage.controller.common.AdminBaseClass;
import com.hunttown.mes.manage.service.AnalysisConfigParamManageService;
import com.hunttown.mes.manage.service.AnalysisManageLoginLogManageService;
import com.hunttown.mes.manage.service.AnalysisManageManageService;
import com.hunttown.mes.manage.service.AnalysisWebsiteParamManageService;
import com.hunttown.mes.rpc.domain.AnalysisManageDTO;
import com.hunttown.mes.rpc.domain.AnalysisManageLoginLogDTO;
import com.hunttown.mes.rpc.domain.enums.api.ClientTypeEnum;
import com.hunttown.mes.rpc.domain.query.AnalysisManageDTOQuery;
import com.hunttown.mes.rpc.domain.vo.SessionVO;
import com.hunttown.mes.common.utils.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.imageio.ImageIO;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.awt.image.RenderedImage;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * @title: 帐号密码登录
 * @author: wangjunfu
 * @date: 2017-07-27
 * @description:
 */
@Controller
@RequestMapping(value = "/login")
public class LoginController {
    private final Logger log = LoggerFactory.getLogger(LoginController.class);

    private final Cache jedisCache;
    private final AnalysisConfigParamManageService configParamService;
    private final AnalysisManageManageService manageService;
    private final AnalysisManageLoginLogManageService loginLogService;
    private final AnalysisWebsiteParamManageService websiteService;

    @Autowired
    public LoginController(Cache jedisCache, AnalysisConfigParamManageService configParamService, AnalysisManageManageService manageService, AnalysisManageLoginLogManageService loginLogService, AnalysisWebsiteParamManageService websiteService) {
        this.jedisCache = jedisCache;
        this.configParamService = configParamService;
        this.manageService = manageService;
        this.loginLogService = loginLogService;
        this.websiteService = websiteService;
    }

    /**
     * 登录
     *
     * @param model model模型
     */
    @RequestMapping(method = RequestMethod.GET)
    public String login(HttpServletRequest request, Model model) throws Exception {
        // 生成时间戳
        Long timespan = Calendar.getInstance().getTimeInMillis();
        model.addAttribute("timestamp", timespan);

        // 生成一个vKey
        String vKey = GetRandomUtils.GetRandom(16);
        model.addAttribute("vKey", vKey);

        //网站名称
        //获取用户企业ID，先从缓存中获取（主要是上次登录保存的，首次登录用户没有），如果不存在则从数据库获取。
        String pin = AdminBaseClass.getPin(request);
        model.addAttribute("websiteName", websiteService.getWebsiteNameFromCache(request, pin));
        model.addAttribute("websiteFullName", websiteService.getWebsiteFullNameFromCache(request, pin));

        //版权信息
        model.addAttribute("copyright", websiteService.getWebsiteCopyrightFromCache(request, pin));

        return "/login/index";
    }

    /**
     * 登录认证（ajax-post）
     * 登录成功以后进行shiro认证
     *
     * @param usermobile 手机号
     * @param userpwd    密码
     * @param vKey       验证码缓存key
     * @param vcode      验证码
     * @param smscode    短信验证码
     * @param signup     记住我COOKIE保存7天
     * @param timestamp  时间戳 限制在1分钟之内登录
     */
    @RequestMapping(value = "/dologin", method = RequestMethod.POST)
    @ResponseBody
    public String loginAction(HttpServletRequest request, HttpServletResponse response, String usermobile, String userpwd, String vKey, String vcode, String smscode, int signup, Long timestamp) {

        Map<String, String> map = new HashMap<String, String>();

        try {

            // 生成新的时间戳
            Long curr_timespan = Calendar.getInstance().getTimeInMillis();
            map.put("timestamp", curr_timespan.toString());

            if (StringUtils.isBlank(usermobile) || StringUtils.isBlank(userpwd) || StringUtils.isBlank(vcode) || timestamp <= 0) {
                map.put("returnMessage", "提示：用户名或密码不能为空！");
                map.put("returnCode", "-1");
                return JSONUtils.toJSON(map);
            } else {
                usermobile = usermobile.trim();
                userpwd = userpwd.trim();
                vcode = vcode.trim();
            }

            // 对比时间戳，必须小于3分钟
            if ((curr_timespan - timestamp) > (3 * 60 * 1000)) {
                // 超过登录时间，重新登录
                map.put("returnMessage", "提示：超过登录时间，请重新登录！");
                map.put("returnCode", "-2");
                return JSONUtils.toJSON(map);
            }

            // 判断验证码是否正确
            String _vcode = jedisCache.get(vKey);
            if (StringUtils.isBlank(_vcode)) {
                map.put("returnMessage", "提示：验证码已过期！");
                map.put("returnCode", "-3");
                return JSONUtils.toJSON(map);
            }
            if (!_vcode.toLowerCase().equals(vcode.toLowerCase())) {
                map.put("returnMessage", "提示：验证码错误！");
                map.put("returnCode", "-4");
                return JSONUtils.toJSON(map);
            }

            // 判断错误登录几次
            String err_count = jedisCache.get(KeyConstants.ADMIN_LOGIN_ERROR_KEY + usermobile);
            if (ConvertUtils.stringToInt(err_count) > 5) {
                map.put("returnMessage", "提示：您已经连续5次错误输入登录密码，系统将锁定2小时！");
                map.put("returnCode", "-5");
                return JSONUtils.toJSON(map);
            }

            // 用户是否存在
            AnalysisManageDTO admin_obj = manageService.getByMobileForLogin(usermobile);  //手机号登录

            if (admin_obj == null) {
                map.put("returnMessage", "提示：用户不存在！");
                map.put("returnCode", "-6");
                return JSONUtils.toJSON(map);
            }

            // 企业ID验证，并判断当前用户是否授权
            if (admin_obj.getEntId() <= 0) {
                return "/help/unauthorized";
            }

            String userpin = admin_obj.getAdminName();

            // 判断密码是否正确
            String password_sha = SHA1Utils.shaEncode(userpin + userpwd);
            assert password_sha != null;    // 断言，如果表达式结果为true，则程序继续执行。否则程序终止。
            if (!password_sha.equals(admin_obj.getPwd())) {
                // 密码错误写入缓存，缓存时间2小时
                jedisCache.incr(KeyConstants.ADMIN_LOGIN_ERROR_KEY + userpin);
                jedisCache.expire(KeyConstants.ADMIN_LOGIN_ERROR_KEY + userpin, 2 * 60 * 60);

                map.put("returnMessage", "提示：密码输入错误！");
                map.put("returnCode", "-7");
                return JSONUtils.toJSON(map);
            }

            // 用户登录成功
            // 1、写 COOKIE
            //参数中配置的缓存存活时间，单位：小时，如果未配置，默认存活24小时
            int time = configParamService.getByParamKey("login-keep-live", 24);
            if (time > 0) {
                time = time * 60 * 60;  //单位：秒
            }

            //如果用户选择了保存7天，则以用户选择的为主
            if (signup == 1) {
                time = 7 * 24 * 60 * 60;
            }

            String onlykey = GetRandomUtils.GetRandom(6);
            String flag = GenFlagUtils.genEncode(onlykey, userpin, password_sha);

            CookieUtils.setCookie(response, KeyConstants.ADMIN_COOKIE, userpin, time);                      // 用户pin
            CookieUtils.setCookie(response, KeyConstants.ADMIN_COOKIE_NICK, admin_obj.getNickName(), time); // 用户nick_name
            CookieUtils.setCookie(response, KeyConstants.ADMIN_COOKIE_STATUS, "loginok", time);  // 用户status
            CookieUtils.setCookie(response, KeyConstants.ADMIN_COOKIE_FLAG, flag, time);                    // 用户flag
            CookieUtils.setCookie(response, KeyConstants.ADMIN_COOKIE_ONLYKEY, onlykey, time);              //用户onlykey

            // 2、写 SESSION
            SessionVO vo = new SessionVO();
            vo.setId(admin_obj.getId());
            vo.setPin(userpin);
            vo.setNick(admin_obj.getNickName());
            vo.setPinStatus("loginok");
            vo.setPinFlag(flag);
            vo.setUpdateTime(new Date());
            jedisCache.oset(KeyConstants.ADMIN_SESSION_CACHE_KEY + userpin, vo, time);

            // 3、写登录日志
            AnalysisManageLoginLogDTO log_obj = new AnalysisManageLoginLogDTO();
            log_obj.setAdminId(admin_obj.getId());
            log_obj.setClientType(ClientTypeEnum.PC.getKey());
            log_obj.setLoginIp(IpUtils.getClientIp(request));
            log_obj.setBrowser(SystemUtils.getBrowserInfo(request));
            log_obj.setLoginTime(new Date());
            log_obj.setDeleteFlag(0);
            loginLogService.insert(log_obj);

            // 打印登录ip
            System.out.println("------------ 以下为IP打印区域 ------------");
            System.out.println("server-ip:" + IpUtils.getServerIp());
            System.out.println("local-ip:" + IpUtils.getLocalIp());
            System.out.println("client-ip:" + IpUtils.getClientIp(request));
            System.out.println("real-ip:" + SystemUtils.getIp(request));

            // 4、更新用户相关信息
            AnalysisManageDTOQuery query = new AnalysisManageDTOQuery();
            query.setW_id(admin_obj.getId());
            query.setLastLoginTime(new Date());
            query.setLastLoginIp(IpUtils.getClientIp(request));
            query.setLoginTimes(admin_obj.getLoginTimes() + 1);
            manageService.updateInfoByQuery(query);

            // 5、更新完信息以后强制刷新用户缓存
            manageService.refreshAdminCache(userpin);

            // 6、登录成功后写入企业ID，否则权限过滤、登录过滤过不去。
            jedisCache.set(KeyConstants.WEBSITE_CURRENT_ENTERPRISE_ID + userpin, admin_obj.getEntId() + "", 180 * 24 * 60 * 60);

            //7、重新写用户session以便切换权限
            ManageRightRoleCacheData.resetUserSession(admin_obj, userpin);

            // 至此登录完毕

        } catch (Exception e) {
            e.printStackTrace();
            map.put("returnMessage", "提示：登录异常！");
            map.put("returnCode", "-8");
            return JSONUtils.toJSON(map);
        }

        OperateCode.CompositionResult(map, 1);
        return JSONUtils.toJSON(map);
    }

    /**
     * 生成验证码
     *
     * @param request  servlet请求
     * @param response servlet请求
     * @param vKey     验证码缓存Key
     */
    @RequestMapping(value = "/getCode", method = RequestMethod.GET)
    public void getCode(HttpServletRequest request, HttpServletResponse response, String vKey) {
        // 调用工具类生成的验证码和验证码图片
        Map<String, Object> codeMap = GenCodeUtils.generateCodeAndPic(0, 0, 0);

        // 将四位数字的验证码保存到Jedis中（1.5分钟）。
        jedisCache.set(vKey, codeMap.get("code").toString(), 90);

        // 禁止图像缓存。
        response.setHeader("Pragma", "no-cache");
        response.setHeader("Cache-Control", "no-cache");
        response.setDateHeader("Expires", -1);
        response.setContentType("image/jpeg");

        // 将图像输出到Servlet输出流中。
        ServletOutputStream sos;
        try {
            sos = response.getOutputStream();
            ImageIO.write((RenderedImage) codeMap.get("codePic"), "jpeg", sos);
            sos.close();
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    /**
     * 退出登录
     */
    @RequestMapping(value = "/logout", method = RequestMethod.GET)
    public void logout(HttpServletRequest request, HttpServletResponse response, Model model) throws Exception {

        // 从Cookie 中取出pin
        String pin = CookieUtils.getCookieByName(request, KeyConstants.ADMIN_COOKIE);

        // 清空 Cookie，将过期时间设置为0 即可
        CookieUtils.setCookie(response, KeyConstants.ADMIN_COOKIE, "unlogin", 0);

        // 清空用户登录Session
        if (pin != null) {
            jedisCache.delete(KeyConstants.ADMIN_SESSION_CACHE_KEY + pin);
            jedisCache.delete(KeyConstants.WEBSITE_CURRENT_ENTERPRISE_ID + pin);
        }

        //网站名称
        model.addAttribute("websiteFullName", websiteService.getWebsiteFullNameFromCache(request, pin));

        response.sendRedirect("/login");
    }

    /**
     * 检查用户是否存在、合法
     *
     * @param response response
     * @param mobile   手机号
     * @return 检查结果
     */
    @RequestMapping(value = "/checkAccount", method = RequestMethod.POST)
    @ResponseBody
    public Map<String, Object> checkAccount(HttpServletResponse response, String mobile) {
        Map<String, Object> map = new HashMap<String, Object>();
        map.put("ok", "err");

        if (StringUtils.isNotBlank(mobile)) {
            AnalysisManageDTO admin_obj = manageService.getByMobileForLogin(mobile);

            if (admin_obj == null) {
                //map.put("returnMessage", "提示：当前用户未授权！");
                return map;
            }

            if (admin_obj.getStopFlag() == 1) {
                //map.put("returnMessage", "提示：当前用户已被锁定！");
                return map;
            }

            //写入企业ID和cookie（有效期10分钟）此方案更改：登录时直接写入和读取
            jedisCache.set(KeyConstants.WEBSITE_CURRENT_ENTERPRISE_ID + admin_obj.getAdminName(), admin_obj.getEntId() + "", 10 * 60); //保留10分钟
            CookieUtils.setCookie(response, KeyConstants.ADMIN_COOKIE, admin_obj.getAdminName(), 10 * 60); //保留10分钟

            //map.put("returnMessage", "提示：用户正常！");
            map.put("ok", "suc");
        }

        return map;
    }
}